package com.lute.controller;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.ide.eclipse.quickfix.jdt.processors.RequestMappingDialog.Method;
import org.springframework.security.oauth2.common.json.JSONException;
import org.springframework.security.oauth2.common.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.lute.model.Approver;
import com.lute.model.Client;
import com.lute.model.ClientAccountingPeriod;
import com.lute.model.ClientAccountingPeriodState;
import com.lute.model.ClientAdmin;
import com.lute.model.ClientProfile;
import com.lute.model.Employee;
import com.lute.model.EmployeeAccountingPeriod;
import com.lute.model.EmployeeAccountingPeriodState;
import com.lute.model.EmployeeEntry;
import com.lute.model.NotepadEntry;
import com.lute.model.User;
import com.lute.model.UserEntitlement;
import com.lute.utils.ServerErrorResponse;

@Controller
public class AccountingPeriodCloseServlet {
	
	@RequestMapping (value="/closeAccountingPeriod",method= RequestMethod.POST, headers = "Content-type=application/json")
	public @ResponseBody String closeAccountingPeriod(@RequestBody String dataJSON, HttpServletRequest request) throws JSONException {
		String result = "";
		String from;
		String clientId;
		JSONObject jsonReq;
		JSONObject jsonRes =  new JSONObject();
		
		HttpSession session = request.getSession(false);
		if(session == null) {
			jsonRes.put("result", ServerErrorResponse.USER_NOT_LOGGED_IN.toString());
			result = jsonRes.toString();
			return result;
		}
		
		System.out.println(dataJSON);
		
		try {
			jsonReq = new JSONObject(dataJSON);
			from = jsonReq.getString("from");
			clientId = jsonReq.getString("clientId");
		} catch(JSONException e) {
			jsonRes.put("result", ServerErrorResponse.MALFORMED_REQUEST.toString());
			result = jsonRes.toString();
			return result;
		}
		
		/* check if json data was not malformed */
		if( (jsonReq.isNull("clientId")) && (jsonReq.isNull("from")) ) {
			jsonRes.put("result",ServerErrorResponse.MALFORMED_REQUEST.toString());
			result = jsonRes.toString();
			return result;
		}
		
		String role = (String)session.getAttribute("role");
		
		/* check  authorization */
		if(!(role.equals("clientAdmin"))) {
			jsonRes.put("result", ServerErrorResponse.USER_NOT_ENTITLED.toString());
			result = jsonRes.toString();
			return result;
		}
		
		int sessionUserId = (Integer)session.getAttribute("sessionUserId");
		int id_client = Integer.parseInt(clientId);
		jsonRes.put("result", "");
		
		ClientProfile clientProfile = null;
		
		try {
			
			clientProfile = UserEntitlement.checkClientAdminPrivilegeToClientProfile(sessionUserId, id_client);
			
			if(clientProfile == null) {
				jsonRes.put("result", ServerErrorResponse.USER_NOT_ENTITLED.toString());
				result = jsonRes.toString();
				return result;
			}
			
			
			String[] tmp = from.split("-");
			GregorianCalendar cal = new GregorianCalendar
										(Integer.parseInt(tmp[0]), Integer.parseInt(tmp[1])-1, Integer.parseInt(tmp[2]));

			
			ClientAccountingPeriod clientPeriod = 
					ClientAccountingPeriod.getClientAccountingPeriodWithEmployeeAccPeriodsBySpecifiedClientFromDB("client.id", id_client,
																												   "date_from", cal);
			if(clientPeriod == null) {
				jsonRes.put("result", ServerErrorResponse.UNKNOWN_ACCOUNTING_PERIOD.toString());
				result = jsonRes.toString();
				System.out.println(result);
				return result;
			}
			
			if(clientPeriod.getClientAccountingPeriodState().equals(ClientAccountingPeriodState.CLOSE.toString())) {
				jsonRes.put("result", ServerErrorResponse.ACCOUNTING_PERIOD_ALREADY_CLOSED.toString());
				result = jsonRes.toString();
				return result;
			}
			
			List<EmployeeAccountingPeriod> periods = clientPeriod.getEmployeeAccountingPeriod();
			periods = EmployeeAccountingPeriod.getEmployeeAccountingPeriodsWithEntriesFromDB(periods);
			
			for(EmployeeAccountingPeriod period : periods) {
				
				EmployeeAccountingPeriod.doAccountingPeriodVerification(period, jsonRes);
				
				if(!(jsonRes.get("result").equals(""))) {
					result = jsonRes.toString();
					System.out.println(result);
					return result;
				}
			}
		
			if(EmployeeAccountingPeriod.isAllCalendarChecked(periods)) {
				ClientAccountingPeriod.closeAccountingPeriod(clientPeriod);
				ClientAccountingPeriod.updateClientAccountingPeriodsInDB(clientPeriod);
			} else {
				jsonRes.put("result", ServerErrorResponse.NOT_ALL_CALENDARS_CHECKED.toString());
				result = jsonRes.toString();
				System.out.println(result);
				return result;
			}
			
			
			// TODO
			// create new accounting period
			int year = Integer.parseInt(tmp[0]);
			int month = Integer.parseInt(tmp[1]);
			int day = Integer.parseInt(tmp[2]);
			
			if (month == 12){
				year++;
				month = 1;
			} else {
				month++;
			}
			
			GregorianCalendar newAccountingPeriodFrom = new GregorianCalendar(year, month-1,1);
			GregorianCalendar newAccountingPeriodTo = new GregorianCalendar(year, month-1, 1);
			newAccountingPeriodTo.add(GregorianCalendar.MONTH, 1);
			newAccountingPeriodTo.add(GregorianCalendar.DATE, -1);
			
			Client currentClient = Client.getClientWithClientAccPeriodByIdFromDB("id_client", id_client);
			
			ClientAccountingPeriod newClientAccountingPeriod = new ClientAccountingPeriod();
			newClientAccountingPeriod.setClient(currentClient);
			newClientAccountingPeriod.setClientAccountingPeriodState(ClientAccountingPeriodState.OPEN.toString());
			newClientAccountingPeriod.setDate_from(newAccountingPeriodFrom);
			newClientAccountingPeriod.setDate_to(newAccountingPeriodTo);
			currentClient.getClientAccountingPeriods().add(newClientAccountingPeriod);
			List<EmployeeAccountingPeriod> employeeAccPeriodList = new ArrayList<EmployeeAccountingPeriod>();
			
			System.out.println("2");
			
			for (EmployeeAccountingPeriod employeeAccountingPeriod : periods) {
				EmployeeAccountingPeriod eap = new EmployeeAccountingPeriod();
				
				eap.setCalendarApprover(employeeAccountingPeriod.getCalendarApprover());
				eap.setCalFrom(newAccountingPeriodFrom);
				eap.setClientAccountingPeriod(newClientAccountingPeriod);
				eap.setEmployeeAccountingPeriodState(EmployeeAccountingPeriodState.INITIAL.toString());
				eap.setEmployeeEntries(new ArrayList<EmployeeEntry>());
				eap.setNotepadEntries(new ArrayList<NotepadEntry>());
				eap.setRejectedBy(null);
				eap.setRejectedByUserRole(null);
				eap.setRejectionDate(null);
				eap.setRejectionReason(null);
				
				if (employeeAccountingPeriod.getEmployee() != null){
					eap.setEmployee(employeeAccountingPeriod.getEmployee());
					Employee employee = Employee.getEmployeeWithEmployeeAccPeriodsFromDB("id_user", (int)employeeAccountingPeriod.getEmployee().getId_user());
					employee.getEmployeeAccountingPeriods().add(eap);
					Employee.updateUserInDB(employee);
				} else {
					eap.setEmployee(null);
				}

				if (employeeAccountingPeriod.getApprover() != null){
					eap.setApprover(employeeAccountingPeriod.getApprover());
					Approver approver = Approver.getApproverWithEmployeeAccPeriodsFromDB("id_user", (int)employeeAccountingPeriod.getApprover().getId_user());
					approver.getApproverAccountingPeriods().add(eap);
					Approver.updateUserInDB(approver);
				} else {
					eap.setApprover(null);
				}
				
				employeeAccPeriodList.add(eap);
				
			}
			
			newClientAccountingPeriod.setEmployeeAccountingPeriod(employeeAccPeriodList);
			
		} catch(NullPointerException npe){
			jsonRes.put("result", ServerErrorResponse.INTERNAL_ERROR.toString());
			result = jsonRes.toString();
			npe.printStackTrace();
			System.out.println(result);
			return result;
		}
		jsonRes.put("result","OK");
		result = jsonRes.toString();
		return result;
	}
}
